package project1;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class MainRequestThread extends Thread {

	private static DatagramSocket requestSocket;
	private static String address;
	private static int port;
	private static Integer nextSentSeqNum;
	
	// a dictionary that maps sequence number to a request thread
	private static Map<Byte, RequestThread> rtl = new HashMap<Byte, RequestThread>();
		
	public MainRequestThread(DatagramSocket requestSocket, String address, int port) {
		super();
		MainRequestThread.requestSocket = requestSocket;
		MainRequestThread.address = address;
		MainRequestThread.port = port;
		MainRequestThread.nextSentSeqNum = 0;
	}
	
	// the value of the current sequence counter (used when generating a new request-response packet)
	private static Byte seqNoCounter = 0;
	
	// returns a new sequence number (used when generating a new request-response packet)
	public static byte getNextSeqNo() {
		synchronized (seqNoCounter) {
			byte ret = seqNoCounter;
			seqNoCounter++;
			return ret;
		}
	}
	
	protected static void decrementSeqNo() {
		synchronized (seqNoCounter) {
			seqNoCounter--;
		}
	}
	
	@Override
	public void run() {
		
		Thread wrt = new WaitResponseThread(requestSocket, MainRequestThread.rtl);		
		wrt.start();
		
	}
	
	protected static void registerNewThread(ICommand commandObj, final byte newSeqNo) {
		commandObj.setSeqNum(newSeqNo);
		final int type = commandObj.getType();
		
		// create new request thread
		RequestThread rt = new RequestThread(commandObj, requestSocket, address, port, new TimeOutBehavior() {
			
			@Override
			public void behave() {
				System.out.println("[SERVER] " + Util.getCommandTypeInEnglish(type) + " (Sequence number " + newSeqNo + ") timed out. ");
				rtl.remove(newSeqNo);
				
			}
		}, -1);
		
		// store the thread-seqNo correspondence
		rtl.put(newSeqNo, rt);
		
		// run new request thread
		rt.start();
	}
	
	private void killResponseThread() {
		if (WaitResponseThread.rrtl != null) {
			for (IResponse response : WaitResponseThread.rrtl.values()) {
				response.close();
				synchronized (response) {
					response.notify();	
				}
			}
		}
	}
	
	protected static void incrementNextSentSeqNum() {
		MainRequestThread.nextSentSeqNum += 1;
	}
	
	protected static int getNextSentSeqNum() {
		return MainRequestThread.nextSentSeqNum;
	}
}
